﻿// ....................................................................................................................
//	Author: Copyright (C) 2012 Ing. Marek Hubal
//	Email: hubal@acasoftware.org
// ....................................................................................................................

using System;

namespace core
{
    /// <summary>Trieda IFileSystem</summary>
	public class IFileSystem
	{
        public const int PATH_TYPE_UNKNOWN = 0;
        public const int PATH_TYPE_ROOT = 1;
        public const int PATH_TYPE_LOCAL_FILE_SYSTEM_ROOT = 2;
        public const int PATH_TYPE_LOCAL_FILE_SYSTEM = 3;
        public const int PATH_TYPE_SAMBA_ROOT = 4;
        public const int PATH_TYPE_SAMBA_COMPUTER = 5;
        public const int PATH_TYPE_SAMBA_COMPUTER_SHARE = 6;
        public const int PATH_TYPE_SAMBA_FILE_SYSTEM = 7;
        public const int PATH_TYPE_ARCHIVE_GZIP = 8;
        public const int PATH_TYPE_ARCHIVE_TAR = 9;
        public const int PATH_TYPE_ARCHIVE_TGZ = 10;
        public const int PATH_TYPE_ARCHIVE_RAR = 11;
        public const int PATH_TYPE_CLOUD_ROOT = 12;
        public const int PATH_TYPE_FTP_FILE_SYSTEM = 13;
        public const int PATH_TYPE_ARCHIVE_ZIP = 14;

        public const int OBJECT_TYPE_UNKNOWN = 0;
        public const int OBJECT_TYPE_DIRECTORY = 1;
        public const int OBJECT_TYPE_FILE = 2;
        public const int OBJECT_TYPE_LOCAL_FS_ROOT = 3;
        public const int OBJECT_TYPE_SAMBA_ROOT = 4;
        public const int OBJECT_TYPE_SAMBA_COMPUTER = 5;
        public const int OBJECT_TYPE_SAMBA_COMPUTER_SHARE = 6;
        public const int OBJECT_TYPE_ROOT = 7;

        public const int FILE_TYPE_UNKNOWN = 0;
        public const int FILE_TYPE_GZIP = 1;
        public const int FILE_TYPE_TAR = 2;
        public const int FILE_TYPE_TGZ = 3;
        public const int FILE_TYPE_RAR = 4;
        public const int FILE_TYPE_ZIP = 5;

        public const int FS_ERROR_UNKNOWN = -1;
        public const int FS_ERROR_UNSUPPORTED = -2;
        public const int FS_ERROR_OBJECT_EXISTS = -3;
        public const int FS_ERROR_FILE_EXISTS = -4;
        public const int FS_ERROR_DIRECTORY_EXISTS = -5;
        public const int FS_ERROR_ACCESS_DENIED = -6;
        public const int FS_ERROR_DEVICE_NOT_READY = -7;
        public const int FS_ERROR_PATH_NOT_FOUND = -8;
        public const int FS_ERROR_DIRECTORY_NOT_EMPTY = -9;
        public const int FS_ERROR_IO_OPERATION = -10;
        public const int FS_ERROR_READ_ONLY = -11;
        public const int FS_ERROR_USER_ABORTED = -12;
        public const int FS_ERROR_READ_ONLY_ATTRIBUTE = -13;
        public const int FS_ERROR_SYSTEM_ATTRIBUTE = -14;
        public const int FS_ERROR_HIDDEN_ATTRIBUTE = -15;
        public const int FS_ERROR_NOT_ENOUGH_SPACE = -16;
        public const int FS_ERROR_READ_ERROR = -17;

        public const int SPECIAL_PATH_ID_USER_DATA = 1;
        public const int SPECIAL_PATH_ID_DESKTOP = 2;
        public const int SPECIAL_PATH_ID_MY_DOCS = 3;
        public const int SPECIAL_PATH_ID_MY_IMAGES = 4;
        public const int SPECIAL_PATH_ID_MY_MUSIC = 5;
        public const int SPECIAL_PATH_ID_MY_VIDEOS = 6;
        public const int SPECIAL_PATH_ID_WINDOWS = 7;
        public const int SPECIAL_PATH_ID_SYSTEM = 8;
        public const int SPECIAL_PATH_ID_START = 9;
        public const int SPECIAL_PATH_ID_TEMP = 10;

        /// <summary>Ziskanie typu cesty</summary>
        /// <param name="pValue">cesta na spracovanie</param>
        /// <returns>typ cesty</returns>
        public static int _GetPathType(string pValue)
        {
            string S;
            return _GetPathType(pValue, out S); // Volam ziskanie typu
        }
        /// <summary>Ziskanie typu cesty a vycistenej cesty</summary>
        /// <param name="pValue">cesta na spracovanie</param>
        /// <param name="Result">vycisteny vysledok</param>
        /// <returns>typ cesty</returns>
        public static int _GetPathType(string pValue, out string Result)
        {
            if (string.IsNullOrWhiteSpace(pValue)) // Prazdny vstup?
            {
                Result = "";
                return PATH_TYPE_ROOT; 
            }

            Result = pValue.Trim();

            if (Result.StartsWith("web://")) // Mozny web storage?
            {
                return PATH_TYPE_CLOUD_ROOT;
            }

            if (Result.StartsWith("ftp://")) // Mozny ftp?
            {
                int I = Result.LastIndexOf('/');
                if (I == 5) // Je len meno servra bez posledneho lomitka?
                {
                    Result += "/"; // Pridam zakladny oddelovac po nazve servera
                    return PATH_TYPE_FTP_FILE_SYSTEM;
                }

                if (I == Result.Length - 1) // Je to posledny oddelovac?
                {
                    I = Result.LastIndexOf('/', Result.Length - 2); // Hladam dalsi
                    if (I == 5) return PATH_TYPE_FTP_FILE_SYSTEM; // Nie je?
                    Result = ICore.DeleteLastExistingChar(Result, '/'); // Zmazem posledny oddelovac
                }

                return PATH_TYPE_FTP_FILE_SYSTEM;
            }

            if (Result.StartsWith("\\\\")) // Mozna samba?
            {
                if (Result.Length == 2) return PATH_TYPE_SAMBA_ROOT; // Samba root?
                int I = Result.IndexOf('\\', 2);
                if ((I == -1) || (I == Result.Length - 1)) // Ziaden dalsi oddelovac alebo je posledny znak?
                {
                    Result = ICore.DeleteLastExistingChar(Result, '\\'); // Zmazem posledny oddelovac
                    return PATH_TYPE_SAMBA_COMPUTER; // Pocitac
                }
                I = Result.IndexOf('\\', I + 1);
                if ((I == -1) || (I == Result.Length - 1)) // Ziaden dalsi oddelovac alebo je posledny znak?
                {
                    Result = ICore.DeleteLastExistingChar(Result, '\\'); // Zmazem posledny oddelovac
                    return PATH_TYPE_SAMBA_COMPUTER_SHARE; // Pocitac
                }
                if (!Result.EndsWith(":\\")) Result = ICore.DeleteLastExistingChar(Result, '\\'); // Zmazem posledny oddelovac
                return PATH_TYPE_SAMBA_FILE_SYSTEM;
            }

            if ((Result.Length > 2) && (char.IsLetter(Result[0])) && (string.Compare(Result, 1, ":\\", 0, 2, true) == 0)) // Mozna lokalna cesta?
            {
                if (Result.Length == 3) return PATH_TYPE_LOCAL_FILE_SYSTEM_ROOT; // Root lokalneho FS
                if (!Result.EndsWith(":\\")) Result = ICore.DeleteLastExistingChar(Result, '\\'); // Zmazem posledny oddelovac
                return PATH_TYPE_LOCAL_FILE_SYSTEM; // Lokalny FS
            }

            return PATH_TYPE_UNKNOWN;
        }
        /// <summary>Pripojenie oddelovaca na koniec cesty</summary>
        /// <param name="pValue">cesta pre spracovanie</param>
        /// <returns>vysledok</returns>
        public static string AppendPathSeparator(string pValue)
        {
            string P;
            switch (_GetPathType(pValue, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_COMPUTER:
                case PATH_TYPE_SAMBA_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_COMPUTER_SHARE:
                    return ICore.AppendUniqueChar(P, '\\'); // Pripojim oddelovac
                case PATH_TYPE_FTP_FILE_SYSTEM:
                    return ICore.AppendUniqueChar(P, '/'); // Pripojim oddelovac
                default: return P;
            }
        }
        /// <summary>Zmazanie oddelovaca z konca cesty</summary>
        /// <param name="pValue">cesta pre spracovanie</param>
        /// <returns>vysledok</returns>
        public static string DeletePathSeparator(string pValue)
        {
            string P;
            _GetPathType(pValue, out P);
            return P; // Vratim upravenu cestu
        }
        /// <summary>Pripojenie hodnoty ku ceste</summary>
        /// <param name="pPath">cesta</param>
        /// <param name="pValue">hodnota</param>
        /// <returns>vysledok</returns>
        public static string AppendToPath(string pPath, string pValue)
        {
            string S = pValue.StartsWith("\\") ? pValue.Substring(1).Trim() : pValue.Trim();
            return DeletePathSeparator(AppendPathSeparator(pPath) + S);
        }
        /// <summary>Ziskanie hlbky cesty</summary>
        /// <param name="pPath">cesta</param>
        /// <returns>hlbka</returns>
        public static int GetPathDepth(string pPath)
        {
            string P;
            switch (_GetPathType(pPath, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM_ROOT: 
                case PATH_TYPE_SAMBA_ROOT:
                    return 1;
                case PATH_TYPE_SAMBA_COMPUTER: 
                    return 2;
                case PATH_TYPE_SAMBA_COMPUTER_SHARE: 
                    return 3;
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                    {
                        int D = 2;
                        int I = 3;
                        while (true)
                        {
                            int I1 = P.IndexOf('\\', I); // Hladam oddelovac
                            if (I1 == -1) return D;
                            D++; I = I1 + 1; // Dalsi oddelovac
                        }
                    }
                case PATH_TYPE_SAMBA_FILE_SYSTEM:
                    {
                        int D = 2;
                        int I = 2;
                        while (true)
                        {
                            int I1 = P.IndexOf('\\', I); // Hladam oddelovac
                            if (I1 == -1) return D;
                            D++; I = I1 + 1; // Dalsi oddelovac
                        }
                    }
                default: return 0;
            }
        }
        /// <summary>Test ci je zadana hodnota podcestou</summary>
        /// <param name="pMainPath">hlavna cesta</param>
        /// <param name="pValue">testovana hodnota</param>
        /// <returns>true / false</returns>
        public static bool IsSubpath(string pMainPath, string pValue)
        {
            string P1, P2;
            _GetPathType(pMainPath, out P1); // Vycistim
            _GetPathType(pValue, out P2);

            return string.Compare(P1, 0, P2, 0, P2.Length, true) == 0; // Otestujem
        }
        /// <summary>Ziskanie typu cesty a vycistenej cesty s analyzou archivov</summary>
        /// <param name="pValue">cesta na spracovanie</param>
        /// <param name="Result">vycisteny vysledok</param>
        /// <returns>typ cesty</returns>
        public static int GetPathType(string pValue, out string Result)
        {
            int R = _GetPathType(pValue, out Result);

            int Start = 0;
            switch (R)
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                    {
                        Start = 3;
                    } break;
                case PATH_TYPE_SAMBA_FILE_SYSTEM:
                    {
                        Start = 2;
                    } break;
                default: return R;
            }

            int I = Result.IndexOf(":\\", Start); // Hladam oddelovac obsahu
            string P = I == -1 ? Result : Result.Substring(0, I); // Ziskam nazov potencionalneho archivu

            switch (GetFileType(P)) // Analyzujem subor
            {
                case FILE_TYPE_GZIP: return PATH_TYPE_ARCHIVE_GZIP;
                case FILE_TYPE_TAR: return PATH_TYPE_ARCHIVE_TAR;
                case FILE_TYPE_TGZ: return PATH_TYPE_ARCHIVE_TGZ;
                case FILE_TYPE_RAR: return PATH_TYPE_ARCHIVE_RAR;
                case FILE_TYPE_ZIP: return PATH_TYPE_ARCHIVE_ZIP;
                default: return R; // Ziaden typ archivu
            }
        }
        /// <summary>Rozdelenie plnej cesty archivu na archivny subor a relativnu cestu vo vnutri archivu</summary>
        /// <param name="pValue">plna cesta</param>
        /// <param name="BaseArchiveFileName">nazov suboru archivu</param>
        /// <param name="RelativePath">relativna cesta</param>
        /// <returns>true / false</returns>
        public static bool SplitFullArchivePath(string pValue, out string BaseArchiveFileName, out string RelativePath)
        {
            BaseArchiveFileName = ""; RelativePath = "";
            string P;
            switch (GetPathType(pValue, out P))
            {
                case PATH_TYPE_ARCHIVE_GZIP:
                case PATH_TYPE_ARCHIVE_TAR:
                case PATH_TYPE_ARCHIVE_RAR:
                case PATH_TYPE_ARCHIVE_TGZ:
                case PATH_TYPE_ARCHIVE_ZIP:
                    {
                        int I = P.IndexOf(":\\", 3); // Hladam oddelovac obsahu
                        if (I == -1)
                        {
                            BaseArchiveFileName = P;
                            RelativePath = "";
                        }
                        else
                        {
                            BaseArchiveFileName = P.Substring(0, I);
                            RelativePath = P.Substring(I + 2);
                        }
                        return true;
                    }
                default: return false;
            }

        }
        /// <summary>Vytvorenie plnej cesty archivu</summary>
        /// <param name="pBaseArchiveFileName">nazov archneho suboru</param>
        /// <param name="pRelativePath">relativna cesta</param>
        /// <returns>vysledok</returns>
        public static string CreateFullArchivePath(string pBaseArchiveFileName, string pRelativePath)
        {
            string P = DeletePathSeparator(pBaseArchiveFileName);
            if (string.IsNullOrEmpty(pRelativePath)) return P + ":\\";
            return DeletePathSeparator(P + ":\\" + pRelativePath);
        }
        /// <summary>Rozdelenie FTP cesty na zlozky</summary>
        /// <param name="pValue">hodnota</param>
        /// <param name="ServerName">nazov servera</param>
        /// <param name="RemotePath">vzdialena cesta</param>
        /// <returns>true / false</returns>
        public static bool SplitFTPPath(string pValue, out string ServerName, out string RemotePath)
        {
            string P;
            switch (_GetPathType(pValue, out P))
            {
                case PATH_TYPE_FTP_FILE_SYSTEM:
                    {
                        int I = P.IndexOf('/', 6); // Hladam oddelovac
                        ServerName = P.Substring(6, I - 6); // Mam server
                        RemotePath = P.Substring(I + 1); // Mam cestu
                        return true;
                    }
                default: // Nie je to FTP
                    {
                        ServerName = "";
                        RemotePath = "";
                        return false;
                    }
            }
        }
        /// <summary>Test pripustnosti nazvu suboru</summary>
        /// <param name="pValue">hodnota</param>
        /// <returns>true / false</returns>
        public static bool IsValidFileName(string pValue)
        {
            if (pValue.IndexOfAny(System.IO.Path.GetInvalidPathChars()) != -1) return false;
            if (pValue.IndexOfAny(System.IO.Path.GetInvalidFileNameChars()) != -1) return false;
            return true;
        }

        /// <summary>Extrahovanie cesty z plneho nazvu</summary>
        /// <param name="pValue">plny nazov na spracovanie</param>
        /// <returns>vysledok</returns>
        public static string ExtractPath(string pValue)
        {
            string P;
            switch (_GetPathType(pValue, out P))
            {
                case PATH_TYPE_SAMBA_COMPUTER: return "\\\\";
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_COMPUTER_SHARE:
                case PATH_TYPE_SAMBA_FILE_SYSTEM:
                    {
                        if (P.EndsWith(":\\")) P = P.Substring(0, P.Length - 2); // Odstranim root archivu
                        int I = P.LastIndexOf('\\');
                        return I == -1 ? "" : DeletePathSeparator(P.Substring(0, I + 1));
                    }
                case PATH_TYPE_FTP_FILE_SYSTEM:
                    {
                        if (P[P.Length - 1] == '/') return ""; // Je to root?
                        int I = P.LastIndexOf('/');
                        P = P.Substring(0, I);
                        if (P.LastIndexOf('/') == 5) P += "/";
                        return P;
                    }
                default: return "";
            }
        }
        /// <summary>Extrahovanie nazvu z plneho nazvu</summary>
        /// <param name="pValue">plny nazov na spracovanie</param>
        /// <returns>vysledok</returns>
        public static string ExtractName(string pValue)
        {
            string P;
            switch (_GetPathType(pValue, out P))
            {
                case PATH_TYPE_SAMBA_COMPUTER: 
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_COMPUTER_SHARE:
                case PATH_TYPE_SAMBA_FILE_SYSTEM:
                    {
                        int I = P.LastIndexOf('\\');
                        return I == -1 ? "" : P.Substring(I + 1);
                    }
                case PATH_TYPE_FTP_FILE_SYSTEM:
                    {
                        if (P[P.Length - 1] == '/') return ""; // Je to root?
                        int I = P.LastIndexOf('/');
                        return P.Substring(I + 1);
                    }
                default: return P;
            }
        }
        /// <summary>Extrahovanie nazvu bez pripony z plneho nazvu</summary>
        /// <param name="pValue">plny nazov na spracovanie</param>
        /// <returns>vysledok</returns>
        public static string ExtractNameOnly(string pValue)
        {
            string P = ExtractName(pValue); // Volam ziskanie mena
            int I = P.LastIndexOf('.'); // Hladam poslednu bodku
            return I == -1 ? P : P.Substring(0, I); // Extrahujem nazov bez pripony
        }
        /// <summary>Extrahovanie pripony z plneho nazvu</summary>
        /// <param name="pValue">plny nazov na spracovanie</param>
        /// <returns>vysledok</returns>
        public static string ExtractExtension(string pValue)
        {
            string P = ExtractName(pValue); // Volam ziskanie mena
            int I = P.LastIndexOf('.'); // Hladam poslednu bodku
            return I == -1 ? "" : P.Substring(I + 1); // Extrahujem priponu
        }
        /// <summary>Extrahovanie root cesty zariadenia</summary>
        /// <param name="pValue">plny nazov</param>
        /// <returns>vysledok</returns>
        public static string ExtractDeviceRoot(string pValue)
        {
            string P;
            switch (_GetPathType(pValue, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM_ROOT:
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                    {
                        return P.Substring(0, 3); // Vratim root
                    }
                case PATH_TYPE_SAMBA_FILE_SYSTEM:
                    {
                        int I = P.IndexOf('\\', P.IndexOf('\\', 2) + 1); // Ziskam odkaz na koniec nazvu share
                        return P.Substring(0, I); // Vratim share
                    }
                case PATH_TYPE_SAMBA_COMPUTER_SHARE: return P;
                default: return "";
            }
        }
        /// <summary>Extrahovanie podcesty</summary>
        /// <param name="pValue">plny nazov</param>
        /// <param name="pDepth">pozadovana hlbka</param>
        /// <returns>vysledok</returns>
        public static string ExtractSubpath(string pValue, int pDepth)
        {
            if (pDepth <= 0) return ""; // Test pripustnosti
            string P;
            _GetPathType(pValue, out P); // Vycistim cestu

            int D = GetPathDepth(P);
            if (pDepth >= D) return P; // Mimo rozsah?

            
            for (int i = D; i > pDepth; i--) P = ExtractPath(P); // Skracujem cestu
            return P; // Mam vysledok
        }

        /// <summary>Ziskanie typu objektu</summary>
        /// <param name="pName">nazov objektu</param>
        /// <returns>-1 neexistuje alebo typ objektu</returns>
        public static int GetObjectType(string pName)
        {
            string P;
            switch (_GetPathType(pName, out P))
            {
                case PATH_TYPE_UNKNOWN: return OBJECT_TYPE_UNKNOWN;
                case PATH_TYPE_ROOT: return OBJECT_TYPE_ROOT;
                case PATH_TYPE_LOCAL_FILE_SYSTEM_ROOT: return OBJECT_TYPE_LOCAL_FS_ROOT;
                case PATH_TYPE_SAMBA_ROOT: return OBJECT_TYPE_SAMBA_ROOT;
                case PATH_TYPE_SAMBA_COMPUTER: return OBJECT_TYPE_SAMBA_COMPUTER;
                case PATH_TYPE_SAMBA_COMPUTER_SHARE: return OBJECT_TYPE_SAMBA_COMPUTER_SHARE;
                default:
                    {
                        IWin32.WIN32_FIND_DATA Data = new IWin32.WIN32_FIND_DATA();
                        IntPtr H = IWin32.Kernel32.FindFirstFile(P, out Data); // Ziskam info o objekte
                        if (H.ToInt32() == IWin32.INVALID_HANDLE_VALUE) return FS_ERROR_PATH_NOT_FOUND;
                        IWin32.Kernel32.FindClose(H); // Uzatvorim hladanie
                        return (Data.dwFileAttributes & IWin32.FILE_ATTRIBUTE_DIRECTORY) != 0 ? OBJECT_TYPE_DIRECTORY : OBJECT_TYPE_FILE; // Vratim podla toho co to je
                    }
            }
        }
        /// <summary>Ziskanie specialnej cesty</summary>
        /// <param name="pID">ID cesty</param>
        /// <returns>cesta alebo prazdny retazec</returns>
        public static string GetSpecialPath(int pID)
        {
            switch (pID)
            {
                case SPECIAL_PATH_ID_USER_DATA:
                    {
                        return System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
                    }
                case SPECIAL_PATH_ID_DESKTOP:
                    {
                        return System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
                    }
                case SPECIAL_PATH_ID_MY_DOCS:
                    {
                        return System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                    }
                case SPECIAL_PATH_ID_MY_IMAGES:
                    {
                        return System.Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
                    }
                case SPECIAL_PATH_ID_MY_MUSIC:
                    {
                        return System.Environment.GetFolderPath(Environment.SpecialFolder.MyMusic);
                    }
                case SPECIAL_PATH_ID_MY_VIDEOS:
                    {
                        return System.Environment.GetFolderPath(Environment.SpecialFolder.MyVideos);
                    }
                case SPECIAL_PATH_ID_WINDOWS:
                    {
                        return System.Environment.GetFolderPath(Environment.SpecialFolder.Windows);
                    }
                case SPECIAL_PATH_ID_SYSTEM:
                    {
                        return System.Environment.GetFolderPath(Environment.SpecialFolder.System);
                    }
                case SPECIAL_PATH_ID_START:
                    {
                        return System.Environment.GetFolderPath(Environment.SpecialFolder.StartMenu);
                    }
                case SPECIAL_PATH_ID_TEMP:
                    {
                        string P = System.Environment.GetEnvironmentVariable("TEMP");
                        if (string.IsNullOrEmpty(P)) P = System.Environment.GetEnvironmentVariable("TMP");
                        return string.IsNullOrEmpty(P) ? "" : P;
                    }
                default: return "";
            }
        }
        /// <summary>Test ci cesta je reparse link</summary>
        /// <param name="pPath">cesta</param>
        /// <returns>true/false</returns>
        public static bool IsReparseLink(string pPath)
        {
            uint R = (uint)IWin32.Kernel32.GetFileAttributes(pPath);
            unchecked { if (R == (uint)IWin32.INVALID_FILE_ATTRIBUTES) return false; }
            return (IWin32.Kernel32.GetFileAttributes(pPath) & IWin32.FILE_ATTRIBUTE_REPARSE_POINT) != 0;
        }
        /// <summary>Ziskanie skutocnej cesty z Reparse linku</summary>
        /// <param name="pPath">reparse link</param>
        /// <returns>skutocna cesta</returns>
        public static string GetRaparseLink(string pPath)
        {
            IntPtr pMem = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(typeof(IWin32.REPARSE_DATA_BUFFER_SYM))); // Alokujem

            IntPtr H = IWin32.Kernel32.CreateFile(pPath, 0, 0, IntPtr.Zero, IWin32.OPEN_EXISTING, IWin32.OPEN_REPARSE_POINT | IWin32.BACKUP_SEMANTICS, IntPtr.Zero); // Otvorim zaznam
            if (H.ToInt32() == -1)
            {
                System.Runtime.InteropServices.Marshal.FreeHGlobal(pMem); // Uvolnenie
                return "";
            }
            int D = 0;
            // Ziskam info
            if (!IWin32.Kernel32.DeviceIoControl(H, IWin32.FSCTL_GET_REPARSE_POINT, IntPtr.Zero, 0, pMem, System.Runtime.InteropServices.Marshal.SizeOf(typeof(IWin32.REPARSE_DATA_BUFFER_SYM)), ref D, IntPtr.Zero))
            {
                IWin32.Kernel32.CloseHandle(H);
                System.Runtime.InteropServices.Marshal.FreeHGlobal(pMem);
                return "";
            }
            IWin32.Kernel32.CloseHandle(H);
            IWin32.REPARSE_DATA_BUFFER_SYM rdb = (IWin32.REPARSE_DATA_BUFFER_SYM)System.Runtime.InteropServices.Marshal.PtrToStructure(pMem, typeof(IWin32.REPARSE_DATA_BUFFER_SYM));

            string Path = "";
            if ((rdb.ReparseTag & 0x80000000) != 0)
            {
                if (rdb.ReparseTag == 0xA000000C)
                {
                    Path = rdb._SymbolicLinkReparseBuffer.PathBuffer;
                }
                else if (rdb.ReparseTag == 0xA0000003)
                {
                    IWin32.REPARSE_DATA_BUFFER_MOUNT rdb1 = (IWin32.REPARSE_DATA_BUFFER_MOUNT)System.Runtime.InteropServices.Marshal.PtrToStructure(pMem, typeof(IWin32.REPARSE_DATA_BUFFER_MOUNT));
                    Path = rdb1._MountPointReparseBuffer.PathBuffer;
                }
                else
                {
                    System.Runtime.InteropServices.Marshal.FreeHGlobal(pMem);
                    return "";
                }
            }
            else
            {
                System.Runtime.InteropServices.Marshal.FreeHGlobal(pMem);
                return "";
            }

            System.Runtime.InteropServices.Marshal.FreeHGlobal(pMem);
            if (Path.StartsWith("\\??\\")) Path = Path.Substring(4, Path.Length - 4);
            if (Path.StartsWith("?\\")) Path = Path.Substring(2, Path.Length - 2);
            return Path;
        }
        /// <summary>Ziskanie asociovanej ikony</summary>
        /// <param name="pExt">pripona</param>
        /// <param name="pAttributes">atributy</param>
        /// <returns>handle ikony</returns>
        public static System.Drawing.Icon GetAssociatedIcon(string pExt, uint pAttributes)
        {
            if (pExt == "") return null;
            if ((pAttributes & IWin32.FILE_ATTRIBUTE_DIRECTORY) != 0) return null;

            IWin32.SHFILEINFO SI = new IWin32.SHFILEINFO();
            // Volam API
            if (IWin32.Shell32.SHGetFileInfo("*." + pExt, pAttributes, ref SI, (uint)System.Runtime.InteropServices.Marshal.SizeOf(SI), IWin32.SHGFI_ICON | IWin32.SHGFI_SMALLICON | IWin32.SHGFI_USEFILEATTRIBUTES) == IntPtr.Zero) return null;
            if (SI.hIcon == IntPtr.Zero) return null;

            System.Drawing.Icon Result = (System.Drawing.Icon)System.Drawing.Icon.FromHandle(SI.hIcon).Clone(); // Vytvorim ikonu
            IWin32.User32.DestroyIcon(SI.hIcon); // Zrusim handle
            return Result; // Vratim objekt ikony
        }
        /// <summary>Ziskanie extrahovanej ikony objektu</summary>
        /// <param name="pName">nazov</param>
        /// <param name="pAttributes">atributy</param>
        /// <returns>objekt ikony alebo null</returns>
        public static System.Drawing.Icon GetExtractedIcon(string pName, uint pAttributes)
        {
            if (pName == "") return null;
            IWin32.SHFILEINFO SI = new IWin32.SHFILEINFO();

            if ((pAttributes & IWin32.FILE_ATTRIBUTE_DIRECTORY) != 0) // Priecinok?
            {
                if (IWin32.Shell32.SHGetFileInfo(pName, pAttributes, ref SI, (uint)System.Runtime.InteropServices.Marshal.SizeOf(SI), IWin32.SHGFI_ICON | IWin32.SHGFI_SMALLICON | IWin32.SHGFI_TYPENAME | IWin32.SHGFI_USEFILEATTRIBUTES) == IntPtr.Zero) return null;
            }
            else
            {
                if (IWin32.Shell32.SHGetFileInfo(pName, 0, ref SI, (uint)System.Runtime.InteropServices.Marshal.SizeOf(SI), IWin32.SHGFI_ICON | IWin32.SHGFI_SMALLICON) == IntPtr.Zero) return null;
            }
            if (SI.hIcon == IntPtr.Zero) return null;

            System.Drawing.Icon Result = (System.Drawing.Icon)System.Drawing.Icon.FromHandle(SI.hIcon).Clone(); // Vytvorim ikonu
            IWin32.User32.DestroyIcon(SI.hIcon); // Zrusim handle
            return Result; // Vratim objekt ikony
        }
        /// <summary>Test ci je zadana cesta disketova mechanika</summary>
        /// <param name="pPath">cesta</param>
        /// <returns>true / false</returns>
        public static bool IsFloppyDevice(string pPath)
        {
            string P;
            switch (_GetPathType(pPath, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_LOCAL_FILE_SYSTEM_ROOT:
                    break;
                default: return false;
            }

            P = P.ToUpper().Substring(0, 2);
            try {
                System.Management.WqlObjectQuery Q = new System.Management.WqlObjectQuery(string.Format("SELECT * FROM Win32_LogicalDisk where DeviceID='{0}'", P));
                System.Management.ManagementObjectSearcher S = new System.Management.ManagementObjectSearcher(Q);
                foreach (System.Management.ManagementObject disk in S.Get())
                {
                    int I = ICore.ToInt(disk["DriveType"]);
                    if (I != 2) return false; // Je to removable?

                    I = ICore.ToInt(disk["MediaType"]);
                    return ((I != 0) && (I != 11) && (I != 12)); // Ak je definovany typ media a nie je to 11 ani 12 - je to floppy
                }
                return false;
            }
            catch
            {
                return false;
            }
        }
        /// <summary>Ziskanie velkosti klustera zariadenia</summary>
        /// <param name="pPath">cesta</param>
        /// <returns>velkost klustera alebo kod chyby</returns>
        public static int GetDeviceClusterSize(string pPath)
        {
            string RootPath = ExtractDeviceRoot(pPath);
            uint U1, U2, U3;
            if (IWin32.Kernel32.GetDiskFreeSpace(RootPath, out U1, out U2, out U3, out U3)) return (int)(U1 * U2);
            return FS_ERROR_UNSUPPORTED;
        }
        /// <summary>Ziskanie dostupneho volneho miesta na zariadenia</summary>
        /// <param name="pPath">cesta</param>
        /// <returns>volne miesto alebo kod chyby</returns>
        public static long GetDeviceFreeSpace(string pPath)
        {
            string RootPath = ExtractDeviceRoot(pPath);
            try
            {
                System.IO.DriveInfo Drv = new System.IO.DriveInfo(RootPath);
                return (long)Drv.AvailableFreeSpace;
            }
            catch
            {
                return FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Ziskanie typu suboru</summary>
        /// <param name="pName">nazov suboru</param>
        /// <returns>typ suboru</returns>
        public static int GetFileType(string pName)
        {
            if (GetObjectType(pName) != OBJECT_TYPE_FILE) return FILE_TYPE_UNKNOWN; // Nie je to subor?
            
            try
            {
                using (System.IO.FileStream File = System.IO.File.OpenRead(pName)) // Otvorim subor
                {
                    byte[] FileData = new byte[512]; // Alokujem buffer
                    int Readed = File.Read(FileData, 0, FileData.Length); // Nacitam

                    if (Readed >= 7)
                    {
                        if ((FileData[0] == 0x52) && (FileData[1] == 0x61) && (FileData[2] == 0x72) && (FileData[3] == 0x21) && (FileData[4] == 0x1A) && (FileData[5] == 0x07) && (FileData[6] == 0x00))
                        {
                            return FILE_TYPE_RAR;
                        }
                        if ((FileData[0] == 0x50) && (FileData[1] == 0x4b) && (FileData[2] == 0x03) && (FileData[3] == 0x04))
                        {
                            return FILE_TYPE_ZIP;
                        }
                    }
                    if (Readed >= 10) 
                    {
                        if ((FileData[0] == 0x1f) && (FileData[1] == 0x8b) && (FileData[2] <= 8)) // Test GZIP
                        {
                            try
                            {
                                using (System.IO.Compression.GZipStream GS = new System.IO.Compression.GZipStream(System.IO.File.OpenRead(pName), System.IO.Compression.CompressionMode.Decompress))
                                {
                                    Readed = GS.Read(FileData, 0, FileData.Length); // Nacitam
                                    if (Readed >= 512)
                                    {
                                        if (INodeList_TAR.IsValidTARHeader(FileData)) return FILE_TYPE_TGZ; // Je to tgz
                                    }
                                }
                            }
                            catch
                            {
                            }
                            return FILE_TYPE_GZIP; // Je to gzip
                        }
                    }
                    if (Readed >= 512)
                    {
                        if (INodeList_TAR.IsValidTARHeader(FileData)) return FILE_TYPE_TAR; // Je to tar                       
                    }
                }
            }
            catch
            {
                return FILE_TYPE_UNKNOWN;
            }
            return FILE_TYPE_UNKNOWN;
        }
        /// <summary>Test ci je subor zasifrovany aplikaciou</summary>
        /// <param name="pName">nazov</param>
        /// <returns>true / false</returns>
        public static bool IsFileEncrypted(string pName)
        {
            if (GetObjectType(pName) != OBJECT_TYPE_FILE) return false; // Otestujem ci je to subor
            int T; long L; string S;
            return IEncryptor.GetEncryptionInfo(pName, out T, out L, out S); // Volam ziskanie typu sifrovania
        }

        /// <summary>Vytvorenie priecinku</summary>
        /// <param name="pName">plny nazov</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int CreateDirectory(string pName)
        {
            string P;
            switch (_GetPathType(pName, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM_ROOT:
                case PATH_TYPE_ROOT:
                case PATH_TYPE_SAMBA_COMPUTER:
                case PATH_TYPE_SAMBA_COMPUTER_SHARE:
                case PATH_TYPE_SAMBA_ROOT:
                    return FS_ERROR_OBJECT_EXISTS;
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_FILE_SYSTEM: break;
                default: return FS_ERROR_UNSUPPORTED;
            }

            int R = GetObjectType(P);
            switch (R)
            {
                case OBJECT_TYPE_FILE: return FS_ERROR_FILE_EXISTS;
                case OBJECT_TYPE_DIRECTORY: return FS_ERROR_DIRECTORY_EXISTS;
                case FS_ERROR_PATH_NOT_FOUND: break;
                default: return FS_ERROR_UNKNOWN;
            }

            if (IWin32.Kernel32.CreateDirectory(P, IntPtr.Zero) != 0) return 0; // Vytvorim priecinok
            R = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
            switch (R)
            {
                case 3: return FS_ERROR_PATH_NOT_FOUND;
                case 5: return IsReadOnlyFileSystem(P) == 1 ? FS_ERROR_READ_ONLY : FS_ERROR_ACCESS_DENIED;
                case 21: return FS_ERROR_DEVICE_NOT_READY;
                default: return FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Vytvorenie priecinku aj s cestou</summary>
        /// <param name="pName">plny nazov</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int CreateFullDirectory(string pName)
        {
            string P;
            switch (_GetPathType(pName, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_FILE_SYSTEM: break;
                case PATH_TYPE_UNKNOWN: return FS_ERROR_UNSUPPORTED;
                default: return FS_ERROR_OBJECT_EXISTS;
            }

            string Parent = ExtractPath(P); // Extrahujem cestu
            int R = CreateFullDirectory(Parent); // Vytvorim cestu
            switch (R)
            {
                case 0:
                case FS_ERROR_OBJECT_EXISTS:
                case FS_ERROR_DIRECTORY_EXISTS: break;
                default: return R;
            }

            return CreateDirectory(P); // Volam vytvorenie posledneho priecinku
        }
        /// <summary>Premenovanie priecinku</summary>
        /// <param name="pCurrentName">aktualny plny nazov</param>
        /// <param name="pNewName">novy nazov bez cesty</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int RenameDirectory(string pCurrentName, string pNewName)
        {
            string P;
            switch (_GetPathType(pCurrentName, out P)) // Podla cesty
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_FILE_SYSTEM: break;
                default: return FS_ERROR_UNSUPPORTED;
            }

            int R = GetObjectType(P); // Otestujem ci je to priecinok
            if (R != OBJECT_TYPE_DIRECTORY) return FS_ERROR_PATH_NOT_FOUND;

            string P1 = pNewName.Trim(); // Pripravim novy nazov
            if (P1.StartsWith("\\")) P1 = P1.Substring(1).Trim();
            if (P1.EndsWith("\\")) P1 = ICore.DeleteLastExistingChar(P1, '\\').Trim();
            if (string.IsNullOrEmpty(P1)) return FS_ERROR_UNSUPPORTED;
            if (P1.IndexOfAny(new char[] { '<', '>', ':', '"', '/', '\\', '|', '?', '*' }) != -1) return FS_ERROR_UNSUPPORTED;

            string P2 = AppendToPath(ExtractPath(P), P1);
            switch (GetObjectType(P2))
            {
                case IFileSystem.FS_ERROR_PATH_NOT_FOUND: break;
                case OBJECT_TYPE_DIRECTORY: return FS_ERROR_DIRECTORY_EXISTS;
                case OBJECT_TYPE_FILE: return FS_ERROR_FILE_EXISTS;
                default: return FS_ERROR_UNSUPPORTED;
            }

            if (IWin32.Kernel32.MoveFile(P, P2) != 0) return 0; // Volam premenovanie
            R = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
            switch (R)
            {
                case 5: return IsReadOnlyFileSystem(P) == 1 ? FS_ERROR_READ_ONLY : FS_ERROR_ACCESS_DENIED;
                default: return FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Vymazanie prazdneho priecinku</summary>
        /// <param name="pName">plny nazov</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int DeleteDirectory(string pName)
        {
            string P;
            switch (_GetPathType(pName, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_FILE_SYSTEM: break;
                default: return FS_ERROR_UNSUPPORTED;
            }

            switch (GetObjectType(P))
            {
                case OBJECT_TYPE_DIRECTORY: break;
                default: return FS_ERROR_PATH_NOT_FOUND;
            }

            IWin32.Kernel32.SetFileAttributes(P, IWin32.FILE_ATTRIBUTE_NORMAL); // Zhodim atributy
            if (IWin32.Kernel32.RemoveDirectory(P) != 0) return 0; // Volam vymazanie
            int R = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
            switch (R)
            {
                case 5: return FS_ERROR_ACCESS_DENIED;
                case 145: return FS_ERROR_DIRECTORY_NOT_EMPTY;
                default: return FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Presun priecinku do recycle bin</summary>
        /// <param name="pName">plny nazov</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int MoveDirectoryToTrash(string pName)
        {
            string P;
            switch (_GetPathType(pName, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_FILE_SYSTEM: break;
                default: return FS_ERROR_UNSUPPORTED;
            }

            switch (GetObjectType(P))
            {
                case OBJECT_TYPE_DIRECTORY: break;
                default: return FS_ERROR_PATH_NOT_FOUND;
            }

            IWin32.SHFILEOPSTRUCT Str = new IWin32.SHFILEOPSTRUCT();
            Str.hwnd = IntPtr.Zero;
            Str.wFunc = IWin32.FO_DELETE;
            Str.pFrom = P + '\0' + '\0';
            Str.fFlags = (ushort)(IWin32.FOF_ALLOWUNDO | IWin32.FOF_NOCONFIRMATION | IWin32.FOF_NOERRORUI | IWin32.FOF_SILENT);
            Str.fAnyOperationsAborted = false;
            Str.hNameMappings = IntPtr.Zero;
            Str.lpszProgressTitle = "";
            Str.pTo = "";

            int R = IWin32.Shell32.SHFileOperation(ref Str);
            switch (R)
            {
                case 0: return Str.fAnyOperationsAborted ? FS_ERROR_USER_ABORTED : 0;
                case 0x74:
                case 0x76:
                case 0x79:
                case 0x81:
                case 0xB7:
                    return FS_ERROR_UNSUPPORTED;
                case 0x78:
                case 0x86:
                case 0x87:
                case 0x88:
                    return FS_ERROR_ACCESS_DENIED;
                default: return FS_ERROR_UNKNOWN;
            }
        }

        /// <summary>Ulozenie retazca do textoveho suboru</summary>
        /// <param name="pFileName">nazov suboru</param>
        /// <param name="pData">data pre zapisanie</param>
        /// <param name="pOverwriteExisting">priznak prepisania existujuceho suboru</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int SaveStringToTextFile(string pFileName, string pData, bool pOverwriteExisting = true)
        {
            string P;
            switch (_GetPathType(pFileName, out P)) // Podla typu cesty
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_FILE_SYSTEM:
                    break;
                default: return FS_ERROR_UNSUPPORTED;
            }

            switch (GetObjectType(P)) // Otestujem na existenicu objektu
            {
                case IFileSystem.FS_ERROR_PATH_NOT_FOUND: break;
                case OBJECT_TYPE_FILE:
                    {
                        if (!pOverwriteExisting) return FS_ERROR_FILE_EXISTS; // Subor existuje?
                    } break;
                default: return FS_ERROR_OBJECT_EXISTS;
            }

            try
            {
                System.IO.File.WriteAllText(P, pData); // Zapisem do suboru
                return 0;
            }
            catch (System.Security.SecurityException) { return FS_ERROR_ACCESS_DENIED; }
            catch (UnauthorizedAccessException) { return FS_ERROR_ACCESS_DENIED; }
            catch(System.IO.IOException) { return FS_ERROR_IO_OPERATION;}
            catch (Exception) { return FS_ERROR_UNKNOWN; }
        }
        /// <summary>Nacitanie obsahu textoveho suboru do retazca</summary>
        /// <param name="pFileName">plny nazov suboru</param>
        /// <param name="Result">nacitany obsah</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int LoadStringFromTextFile(string pFileName, out string Result)
        {
            string P; Result = "";
            switch (_GetPathType(pFileName, out P)) // Podla typu cesty
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_FILE_SYSTEM:
                    break;
                default: return FS_ERROR_UNSUPPORTED;
            }

            switch (GetObjectType(P)) // Otestujem na existenicu objektu
            {
                case OBJECT_TYPE_FILE: break;
                default: return FS_ERROR_PATH_NOT_FOUND;
            }

            try
            {
                Result = System.IO.File.ReadAllText(P); // Zapisem do suboru
                return 0;
            }
            catch (System.Security.SecurityException) { return FS_ERROR_ACCESS_DENIED; }
            catch (UnauthorizedAccessException) { return FS_ERROR_ACCESS_DENIED; }
            catch (System.IO.IOException) { return FS_ERROR_IO_OPERATION; }
            catch (Exception) { return FS_ERROR_UNKNOWN; }
        }
        /// <summary>Premenovanie suboru</summary>
        /// <param name="pCurrentName">aktualny plny nazov</param>
        /// <param name="pNewName">novy nazov bez cesty</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int RenameFile(string pCurrentName, string pNewName)
        {
            string P;
            switch (_GetPathType(pCurrentName, out P)) // Podla cesty
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_FILE_SYSTEM: break;
                default: return FS_ERROR_UNSUPPORTED;
            }

            int R = GetObjectType(P); // Otestujem ci je to priecinok
            if (R != OBJECT_TYPE_FILE) return FS_ERROR_PATH_NOT_FOUND;

            string P1 = pNewName.Trim(); // Pripravim novy nazov
            if (P1.StartsWith("\\")) P1 = P1.Substring(1).Trim();
            if (P1.EndsWith("\\")) P1 = ICore.DeleteLastExistingChar(P1, '\\').Trim();
            if (string.IsNullOrEmpty(P1)) return FS_ERROR_UNSUPPORTED;
            if (P1.IndexOfAny(new char[] { '<', '>', ':', '"', '/', '\\', '|', '?', '*' }) != -1) return FS_ERROR_UNSUPPORTED;

            string P2 = AppendToPath(ExtractPath(P), P1);
            if (string.Compare(P, P2, true) != 0)
            {
                switch (GetObjectType(P2))
                {
                    case IFileSystem.FS_ERROR_PATH_NOT_FOUND: break;
                    case OBJECT_TYPE_DIRECTORY: return FS_ERROR_DIRECTORY_EXISTS;
                    case OBJECT_TYPE_FILE: return FS_ERROR_FILE_EXISTS;
                    default: return FS_ERROR_UNSUPPORTED;
                }
            }

            if (IWin32.Kernel32.MoveFile(P, P2) != 0) return 0; // Volam premenovanie
            R = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
            switch (R)
            {
                case 5: return IsReadOnlyFileSystem(P) == 1 ? FS_ERROR_READ_ONLY : FS_ERROR_ACCESS_DENIED;
                default: return FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Vymazanie suboru</summary>
        /// <param name="pName">plny nazov</param>
        /// <param name="pIgnoreAttr_ReadOnly">priznak ignorovania atributy readonly</param>
        /// <param name="pIgnoreAttr_Hidden">priznak ignorovania atributy hidden</param>
        /// <param name="pIgnoreAttr_System">priznak ignorovania atributy system</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int DeleteFile(string pName, bool pIgnoreAttr_ReadOnly = false, bool pIgnoreAttr_Hidden = false, bool pIgnoreAttr_System = false)
        {
            string P;
            switch (_GetPathType(pName, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_FILE_SYSTEM: break;
                default: return FS_ERROR_UNSUPPORTED;
            }

            switch (GetObjectType(P))
            {
                case OBJECT_TYPE_FILE: break;
                default: return FS_ERROR_PATH_NOT_FOUND;
            }

            uint Attr = IWin32.Kernel32.GetFileAttributes(P);
            if (Attr != IWin32.INVALID_FILE_ATTRIBUTES)
            {
                if ((!pIgnoreAttr_Hidden) | (!pIgnoreAttr_ReadOnly) | (!pIgnoreAttr_System))
                {
                    if ((!pIgnoreAttr_ReadOnly) && ((Attr & IWin32.FILE_ATTRIBUTE_READONLY) != 0)) return FS_ERROR_READ_ONLY_ATTRIBUTE;
                    if ((!pIgnoreAttr_System) && ((Attr & IWin32.FILE_ATTRIBUTE_SYSTEM) != 0)) return FS_ERROR_SYSTEM_ATTRIBUTE;
                    if ((!pIgnoreAttr_Hidden) && ((Attr & IWin32.FILE_ATTRIBUTE_HIDDEN) != 0)) return FS_ERROR_HIDDEN_ATTRIBUTE;
                }
                if (!IWin32.Kernel32.SetFileAttributes(P, IWin32.FILE_ATTRIBUTE_NORMAL)) return FS_ERROR_ACCESS_DENIED;
            }

            if (IWin32.Kernel32.DeleteFile(P) != 0) return 0; // Volam vymazanie
            if (Attr != IWin32.INVALID_FILE_ATTRIBUTES) IWin32.Kernel32.SetFileAttributes(P, Attr); // Vratim spat atributy

            int R = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
            switch (R)
            {
                case 5: return FS_ERROR_ACCESS_DENIED;
                default: return FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Presun suboru do recycle bin</summary>
        /// <param name="pName">plny nazov</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int MoveFileToTrash(string pName)
        {
            string P;
            switch (_GetPathType(pName, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_FILE_SYSTEM: break;
                default: return FS_ERROR_UNSUPPORTED;
            }

            switch (GetObjectType(P))
            {
                case OBJECT_TYPE_FILE: break;
                default: return FS_ERROR_PATH_NOT_FOUND;
            }

            IWin32.SHFILEOPSTRUCT Str = new IWin32.SHFILEOPSTRUCT();
            Str.hwnd = IntPtr.Zero;// IApp.AppForm.Handle;
            Str.wFunc = IWin32.FO_DELETE;
            Str.pFrom = P + '\0' + '\0';
            Str.fFlags = (ushort)(IWin32.FOF_ALLOWUNDO | IWin32.FOF_NOCONFIRMATION | IWin32.FOF_NOERRORUI | IWin32.FOF_SILENT);
            Str.fAnyOperationsAborted = false;
            Str.hNameMappings = IntPtr.Zero;
            Str.lpszProgressTitle = "";
            Str.pTo = "";

            int R = IWin32.Shell32.SHFileOperation(ref Str);
            switch (R)
            {
                case 0: return Str.fAnyOperationsAborted ? FS_ERROR_USER_ABORTED : 0;
                case 0x74:
                case 0x76:
                case 0x79:
                case 0x81:
                case 0xB7:
                    return FS_ERROR_UNSUPPORTED;
                case 0x78:
                case 0x86:
                case 0x87:
                case 0x88:
                    return FS_ERROR_ACCESS_DENIED;
                default: return FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Ziskanie dlzky suboru</summary>
        /// <param name="pName">nazov</param>
        /// <returns>dlzka alebo kod chyby</returns>
        public static long GetFileSize(string pName)
        {
            string P;
            switch (_GetPathType(pName, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_FILE_SYSTEM: break;
                default: return FS_ERROR_UNSUPPORTED;
            }
            switch (GetObjectType(P))
            {
                case OBJECT_TYPE_FILE: break;
                default: return FS_ERROR_PATH_NOT_FOUND;
            }
            try
            {
                return new System.IO.FileInfo(P).Length;
            }
            catch
            {
                return FS_ERROR_UNKNOWN;
            }
        }

        /// <summary>Ziskanie atributov</summary>
        /// <param name="pName">nazov</param>
        /// <param name="Result">atributy</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int GetAttributes(string pName, out uint Result)
        {
            string P; Result = IWin32.INVALID_FILE_ATTRIBUTES;
            switch (_GetPathType(pName, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_FILE_SYSTEM: break;
                default: return FS_ERROR_UNSUPPORTED;
            }

            Result = IWin32.Kernel32.GetFileAttributes(pName);
            return Result == IWin32.INVALID_FILE_ATTRIBUTES ? FS_ERROR_UNKNOWN : 0;
        }
        /// <summary>Ziskanie atributov</summary>
        /// <param name="pName">nazov</param>
        /// <param name="Result">atributy</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int GetAttributes(string pName, out uint Result, out DateTime DCreate, out DateTime DModify, out DateTime DLastAccess)
        {
            string P; Result = IWin32.INVALID_FILE_ATTRIBUTES; DCreate = DModify = DLastAccess = DateTime.MinValue;
            switch (_GetPathType(pName, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_FILE_SYSTEM: break;
                default: return FS_ERROR_UNSUPPORTED;
            }

            try
            {
                System.IO.FileInfo FI = new System.IO.FileInfo(pName);
                Result = (uint)FI.Attributes; DCreate = FI.CreationTime; DModify = FI.LastWriteTime; DLastAccess = FI.LastAccessTime;
                return 0;
            }
            catch
            {
                return FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Nastavenie atributov suboru alebo priecinku</summary>
        /// <param name="pName">nazov</param>
        /// <param name="pAttributes">nove atributy</param>
        /// <param name="pDCreate">datum vytvorenia</param>
        /// <param name="pDModify">datum modifikacie</param>
        /// <param name="pDLastAccess">datum posledneho pristupu</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int SetAttributes(string pName, uint pAttributes, DateTime pDCreate, DateTime pDModify, DateTime pDLastAccess)
        {
            string P;
            switch (_GetPathType(pName, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_SAMBA_FILE_SYSTEM: break;
                default: return FS_ERROR_UNSUPPORTED;
            }

            ulong D1 = pDCreate == DateTime.MinValue ? 0 : (ulong)pDCreate.ToFileTime();
            ulong D2 = pDModify == DateTime.MinValue ? 0 : (ulong)pDModify.ToFileTime();
            ulong D3 = pDLastAccess == DateTime.MinValue ? 0 : (ulong)pDLastAccess.ToFileTime();

            IWin32.Kernel32.SetFileAttributes(P, IWin32.FILE_ATTRIBUTE_NORMAL);
            core2.SetFileDateTime(P, D1, D2, D3);

            if (!IWin32.Kernel32.SetFileAttributes(P, pAttributes))
            {
                int R = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
                switch (R)
                {
                    case 5: return FS_ERROR_ACCESS_DENIED;
                    default: return FS_ERROR_UNKNOWN;
                }
            }
            return 0;
        }

        /// <summary>Ziskanie nazvu zariadenia</summary>
        /// <param name="pPath">cesta</param>
        /// <param name="Result">vysledok</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int GetDeviceName(string pPath, out string Result)
        {
            string P; Result = "";
            switch (_GetPathType(pPath, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_LOCAL_FILE_SYSTEM_ROOT:
                    break;
                default: return FS_ERROR_UNSUPPORTED; // Nepodporovane
            }

            P = ExtractDeviceRoot(P); // Extrahujem root cestu
            
            System.Text.StringBuilder B = new System.Text.StringBuilder(2048);
            uint U;

            // Volam Win32 API
            if (IWin32.Kernel32.GetVolumeInformation(P, B, 256, out U, out U, out U, null, 0))
            {
                Result = B.ToString();
                return 0;
            }

            // Chyba
            int R = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
            switch (R)
            {
                default: return FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Nastavenie nazvu zariadenia</summary>
        /// <param name="pPath">cesta</param>
        /// <param name="pName">nazov</param>
        /// <returns>0 alebo kod chyby</returns>
        public static int SetDeviceName(string pPath, string pName)
        {
            string P;
            switch (_GetPathType(pPath, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_LOCAL_FILE_SYSTEM_ROOT:
                    break;
                default: return FS_ERROR_UNSUPPORTED; // Nepodporovane
            }

            P = ExtractDeviceRoot(P); // Extrahujem root cestu
            
            if (IWin32.Kernel32.SetVolumeLabel(P, pName)) return 0; // Volam nastavenie
            
            // Chyba
            int R = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
            switch (R)
            {
                case 5: return IsReadOnlyFileSystem(P) == 1 ? FS_ERROR_READ_ONLY : FS_ERROR_ACCESS_DENIED;
                default: return FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Test ci je suborovy system read only</summary>
        /// <param name="pPath">cesta</param>
        /// <returns>0 - nie je, 1 - je alebo kod chyby</returns>
        public static int IsReadOnlyFileSystem(string pPath)
        {
            string P;
            switch (_GetPathType(pPath, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_LOCAL_FILE_SYSTEM_ROOT:
                    break;
                default: return FS_ERROR_UNSUPPORTED; // Nepodporovane
            }

            P = ExtractDeviceRoot(P); // Extrahujem root cestu

            uint U1, U2, U3;

            if (IWin32.Kernel32.GetVolumeInformation(P, null, 0, out U1, out U2, out U3, null, 0))
            {
                return ((U3 & 0x00080000) != 0) ? 1 : 0;
            }

            // Chyba
            int R = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
            switch (R)
            {
                default: return FS_ERROR_UNKNOWN;
            }
        }

        /// <summary>Test, ci zadana je cesta na CD/DVD zariadeni</summary>
        /// <param name="pPath">cesta</param>
        /// <returns>0 - nie je, 1 - je, alebo kod chyby</returns>
        public static int IsCDDevice(string pPath)
        {
            string P;
            switch (_GetPathType(pPath, out P))
            {
                case PATH_TYPE_LOCAL_FILE_SYSTEM:
                case PATH_TYPE_LOCAL_FILE_SYSTEM_ROOT:
                    break;
                default: return FS_ERROR_UNSUPPORTED;
            }

            string RootP = ExtractDeviceRoot(P); // Ziskam root cestu
            try
            {
                return new System.IO.DriveInfo(RootP).DriveType == System.IO.DriveType.CDRom ? 1 : 0;
            }
            catch
            {
                return FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Vysunutie media</summary>
        /// <param name="pPath">cesta</param>
        /// <returns>0 - OK alebo kod chyby</returns>
        public static int EjectCD(string pPath)
        {
            if (IsCDDevice(pPath) != 1) return FS_ERROR_UNSUPPORTED; // Nie je CD zariadenie?
            using (core2namespace.ICDDriveReaded Drv = new core2namespace.ICDDriveReaded())
            {
                Drv.Open(pPath[0]);
                return Drv.EjectCD();
            }

            /*
            string FN = new string(new char[] { '\\', '\\', '.', '\\', RootP[0], ':', '\0' });

            // Otvorim CD zariadenie
            IntPtr FHandle = IWin32.Kernel32.CreateFile(FN, IWin32.GENERIC_READ, IWin32.FILE_SHARE_READ, IntPtr.Zero, IWin32.OPEN_EXISTING, 0, IntPtr.Zero);
            if (FHandle.ToInt32() == IWin32.INVALID_HANDLE_VALUE) return FS_ERROR_IO_OPERATION;

            int I = 0; // Vysunie CD
            bool B = IWin32.Kernel32.DeviceIoControl(FHandle, IWin32.IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, ref I, IntPtr.Zero);
            IWin32.Kernel32.CloseHandle(FHandle); // Uzatvorim handle

            return B ? 0 : FS_ERROR_IO_OPERATION;
             */

        }
        /// <summary>Vysunutie media</summary>
        /// <param name="pPath">cesta</param>
        /// <returns>0 - OK alebo kod chyby</returns>
        public static int InsertCD(string pPath)
        {
            if (IsCDDevice(pPath) != 1) return FS_ERROR_UNSUPPORTED; // Nie je CD zariadenie?
            using (core2namespace.ICDDriveReaded Drv = new core2namespace.ICDDriveReaded())
            {
                Drv.Open(pPath[0]);
                return Drv.InsertCD();
            }

        }
        /// <summary>Vysunutie media</summary>
        /// <param name="pPath">cesta</param>
        /// <returns>0 - OK alebo kod chyby</returns>
        public static int EjectInsertCD(string pPath)
        {
            if (IsCDDevice(pPath) != 1) return FS_ERROR_UNSUPPORTED; // Nie je CD zariadenie?
            using (core2namespace.ICDDriveReaded Drv = new core2namespace.ICDDriveReaded())
            {
                Drv.Open(pPath[0]);
                return Drv.IsCDReady() != 1 ? Drv.InsertCD() : Drv.EjectCD();
            }
        }
    }
}
